package com.hmc.modules.sjfx.controller.glsjfx;

import com.hmc.common.utils.Result;
import com.hmc.modules.sjfx.dto.glsjfx.GgHfDTO;
import com.hmc.modules.sjfx.service.lashent.LashentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.mahout.fpm.pfpgrowth.FPGrowthDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import smile.association.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.SequenceFile.Reader;
import org.apache.hadoop.io.Text;
import org.apache.mahout.common.Pair;
import org.apache.mahout.fpm.pfpgrowth.convertors.string.TopKStringPatterns;

/**
 * 关联关系挖掘：钢管焊缝抗拉强度
 */
@AllArgsConstructor
@RestController
@RequestMapping("glsjfx/klqd")
@Tag(name = "关联关系挖掘：钢管焊缝抗拉强度")
public class AssociationConteoller {
    @Autowired
    private LashentService lashentService;

    /**
     * 关联关系挖掘：钢管焊缝抗拉强度,使用 mahout 库
     */
    @GetMapping("mahout")
    @Operation(summary = "关联关系挖掘：钢管焊缝抗拉强度")
    public Result<Boolean> getGlsjfxKlqdMahout() throws Exception {
        /**
         * 获取数据：GgHfDTO
         * 屈服强度 YS
         * 抗拉强度 TS
         * 屈强比 YIELD_RATE
         * 拉伸率 EL
         */
        ArrayList<GgHfDTO> datagghf = lashentService.getGlsjfxKlqd();

        /**
         * Mahout 实现关联规则挖掘
         */

        // 将数据转换为适合Mahout的格式
        ArrayList<String> data = new ArrayList<>();
        for (GgHfDTO ggHfDTO : datagghf) {
            data.add(ggHfDTO.getYs() + "," + ggHfDTO.getTs() + "," + ggHfDTO.getYieldRate() + "," + ggHfDTO.getEl());
        }

        // 将数据写入 SequenceFile
        Configuration conf = new Configuration();
        Path path = new Path("mes-admin/src/main/resources/seq/data.seq");
        FileSystem fs = FileSystem.get(conf);
        SequenceFile.Writer writer = new SequenceFile.Writer(fs, conf, path, LongWritable.class, Text.class);
        long key = 0;
        for (String value : data) {
            writer.append(new LongWritable(key++), new Text(value));
        }
        writer.close();

        // 运行 FPGrowth
        String[] fpGrowthArgs = { "-i", "data.seq", "-o", "output", "-k", "10", "-method", "mapreduce" };
        FPGrowthDriver.main(fpGrowthArgs);

        // 读取输出
        SequenceFile.Reader reader = new SequenceFile.Reader(fs, new Path("output/frequentpatterns/part-r-00000"), conf);
        Text tkey = new Text();
        TopKStringPatterns value = new TopKStringPatterns();
        while (reader.next(tkey, value)) {
            System.out.println(tkey.toString() + " : " + value.toString());
        }
        reader.close();


        return null;
    }


    /**
     * 关联关系挖掘：钢管焊缝抗拉强度,使用 smile 库
     */
    @GetMapping("smile")
    @Operation(summary = "关联关系挖掘：钢管焊缝抗拉强度")
    public Result<List<AssociationRule>> getGlsjfxKlqd() {

        /**
         * 获取数据：GgHfDTO
         * 屈服强度 YS
         * 抗拉强度 TS
         * 屈强比 YIELD_RATE
         * 拉伸率 EL
         */
        ArrayList<GgHfDTO> datagghf = lashentService.getGlsjfxKlqd();

        // 将数据转换为适合FPTree的格式
        int[][] data = convertData(datagghf);

        FPTree fptree = null;
        if (data != null) {
            fptree = FPTree.of(2, data); // 支持度阈值为2
            fptree = FPTree.of(0.3, data); // 支持度阈值为2
        }

        /**
         * 使用FPGrowth找到频繁项集
         * 返回一个流，其中包含所有频繁项集及其支持度。
         *
         * ItemSet：
         * items- 项集中的项目。
         * support- 项集的支持度。
         */
        Stream<ItemSet> itemsets = null;
        if (fptree != null) {
            itemsets = FPGrowth.apply(fptree);
        }

        /**
         * 使用ARM类查找频繁项集
         * 返回一个流，其中包含所有频繁项集及其支持度。
         *
         * AssociationRule：
         * antecedent- 关联规则的先行项集 （LHS）。
         * consequent- 关联规则的后续项集 （RHS）。
         * support- 数据集中包含项集的实例的比例。
         * confidence- 包含结果的实例的百分比 和先行者一起超过实例数 仅包含先行者。
         * lift- 前因后果同时发生的频率要高出多少倍 如果它们在统计上是独立的，则比预期的要好。
         * leverage- 规则的概率与预期之间的差值 如果项目在统计上是独立的，则概率。
         *
         */
        Stream<AssociationRule> apply = ARM.apply(0.3, fptree);

        // 打印所有频繁项集及其支持度
        itemsets.forEach(itemSet -> {
            System.out.println(itemSet.toString());
        });

        /**
         * AssociationRule：
         * antecedent- 关联规则的先行项集 （LHS）。
         * consequent- 关联规则的后续项集 （RHS）。
         * support- 数据集中包含项集的实例的比例。
         * confidence- 包含结果的实例的百分比 和先行者一起超过实例数 仅包含先行者。
         * lift- 前因后果同时发生的频率要高出多少倍 如果它们在统计上是独立的，则比预期的要好。
         * leverage- 规则的概率与预期之间的差值 如果项目在统计上是独立的，则概率。
         */
//        apply.forEach(associationRule -> {
//            System.out.println(associationRule.toString());
//        });
        List<AssociationRule> associationRules = apply.toList();

        associationRules.forEach(associationRule -> {
            System.out.println(associationRule.toString());
        });

        return new Result<List<AssociationRule>>().ok(associationRules);
    }

    /**
     * 将数据转换为适合FPTree的格式
     *
     * @param datagghf
     * @return
     */
    private int[][] convertData(ArrayList<GgHfDTO> datagghf) {

        // 将数据转换为适合FPTree的格式
        int[][] data = new int[datagghf.size()][4];
        for (int i = 0; i < datagghf.size(); i++) {
            data[i][0] = Integer.parseInt(datagghf.get(i).getYs());
            data[i][1] = Integer.parseInt(datagghf.get(i).getTs());
            if (Double.valueOf(datagghf.get(i).getYieldRate()) < 1.0){
                data[i][2] = 1;
            }else {
                data[i][2] = Integer.parseInt(datagghf.get(i).getYieldRate());
            }
            data[i][3] = Integer.parseInt(datagghf.get(i).getEl());
        }
        return data;
    }
}
